package com.angus.auth.service.front;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import com.angus.api.front.RemoteFrontUserService;
import com.angus.api.front.domain.FrontSendCode;
import com.angus.common.core.constant.SecurityConstants;
import com.angus.common.core.domain.R;
import com.angus.common.core.enums.DeviceType;
import com.angus.common.core.enums.SendCodeScene;
import com.angus.common.core.exception.ServiceException;
import com.angus.common.core.utils.ip.IpUtils;
import com.angus.common.security.config.SendCodeConfig;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;

/**
 * @author lineCode
 */
@Component
public class SendCodeService {

    @Resource
    private SendCodeConfig sendCodeConfig;

    @Resource
    private RemoteFrontUserService remoteFrontUserService;

    @Resource
    private AliyunSmsService aliyunSmsService;

    @Resource
    private EmailSendService emailSendService;

    public void sendSendCode(String device, Integer type,Integer scene){
        SendCodeScene sceneEnum = SendCodeScene.getCodeBySceneCode(scene);
        Assert.notNull(sceneEnum, "验证码场景({})不存在",scene);
        String code = createSendCode(device,scene, type, IpUtils.getIpAddr());
        if (type == DeviceType.PHONE.getTypeFlag()){
            // 发送阿里云短信
            aliyunSmsService.sendSms(device,code);
        }else{
            // 发送邮件
            emailSendService.sendEmailCode(device,code);
        }
    }

    private String createSendCode(String device,Integer scene, Integer type, String ip) {
        // 查询最后一次发送的验证码 (当天)
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        LocalDate now = LocalDateTime.now().toLocalDate();
        R<FrontSendCode> lastSendCodeResult = remoteFrontUserService.queryLastSendCode(device,scene,now.format(formatter),SecurityConstants.INNER);

        if (R.FAIL == lastSendCodeResult.getCode()) {
            throw new ServiceException(lastSendCodeResult.getMsg());
        }
        FrontSendCode lastSendCode = lastSendCodeResult.getData();
        if (Objects.nonNull(lastSendCode)){
            if (lastSendCode.getTodayIndex()>= sendCodeConfig.getMaxSendCount()){
                throw new ServiceException("今日发送短信次数已达到5次");
            }
            // 正确的时间顺序：过去时间在前，当前时间在后
            Duration diff = LocalDateTimeUtil.between(lastSendCode.getCreateTime(), LocalDateTime.now());
            // 检查配置是否存在, 不存在的话，默认60秒间隔
            Duration sendFrequency = Optional.ofNullable(sendCodeConfig)
                    .map(SendCodeConfig::getSendFrequency)
                    .orElse(Duration.ofSeconds(60));
            // 检查是否首次发送
            if(diff.toMillis() < sendFrequency.toMillis()){
                // 计算剩余可发送时间，提供更友好的提示
                long remainingSeconds = (sendFrequency.toMillis() - diff.toMillis()) / 1000 + 1;
                throw new ServiceException("短信发送过于频繁，请" + remainingSeconds + "秒后再试");
            }
        }
        // 如果配置结果为空
        if (sendCodeConfig != null) {
            String code = String.valueOf(RandomUtil.randomInt(sendCodeConfig.getBeginCode(), sendCodeConfig.getEndCode() + 1));
            FrontSendCode newSendCode = FrontSendCode.builder().device(device)
                    .scene(scene)
                    .todayIndex(Objects.nonNull(lastSendCode)?lastSendCode.getTodayIndex()+1:1)
                    .createIp(ip)
                    .used(false)
                    .code(code)
                    .type(type)
                    .sendStatus(1)
                    .build();
            newSendCode.setCreateTime(LocalDateTime.now());
            remoteFrontUserService.saveSendCode(newSendCode, SecurityConstants.INNER);
            return code;
        }
        return null;
    }

    public boolean checkSendCode(String device, String code, SendCodeScene scene) {
        // (当天)
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        LocalDateTime now = LocalDateTime.now();
        R<FrontSendCode> lastSendCodeResult = remoteFrontUserService.queryLastSendCode(device, scene.getSceneCode(), now.toLocalDate().format(formatter), SecurityConstants.INNER);
        if (R.FAIL == lastSendCodeResult.getCode()) {
            throw new ServiceException(lastSendCodeResult.getMsg());
        }
        FrontSendCode lastSendCode = lastSendCodeResult.getData();
        if (Objects.nonNull(lastSendCode)){
            LocalDateTime expireTime = lastSendCode.getCreateTime().plus(sendCodeConfig.getExpireTimes());
            if (now.isAfter(expireTime)) {
                throw new ServiceException("验证码已过期");
            }
            if(!code.equals(lastSendCode.getCode())){
                throw new ServiceException("验证码错误");
            }
            if (lastSendCode.getUsed()){
                throw new ServiceException("验证码已使用");
            }
            lastSendCode.setUsed(true);
            lastSendCode.setUseIp(IpUtils.getIpAddr());
            lastSendCode.setUseTime(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()));
            remoteFrontUserService.updateSendCode(lastSendCode, SecurityConstants.INNER);
            return Boolean.TRUE;
        }else{
            throw new ServiceException("请先发送验证码");
        }
    }
}
